import axios from "axios"
import type { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ElMessage as messageUtil, ElNotification as notification, ElLoading } from 'element-plus'
import { getToken } from "@/common/utils"
import { useUserStore } from "@/store"
import router from "@/router"
import { tokenKey, } from "./config"
import { globalLoadingMaskBgColor } from "@/theme/config"

const baseConfig: AxiosRequestConfig = {
   timeout: 8000,
   baseURL: import.meta.env.VITE_BASE_URL,
   withCredentials: true,
}

export const service = axios.create(baseConfig)

let cancelreq: any
const cancelMsgSymbol = '@cancel@'

let elLoading: any

export interface myAxiosRequestConfig extends AxiosRequestConfig {
   /**是否关闭全局加载，默认启用  */
   closeGlobalLoading?: boolean
   /**加载图标下方显示的文字 */
   loadingTip?: string
   /**请求成功但业务状态码是失败的,此时是否关闭自动的错误提示，默认打开 */
   closeErrTip?: boolean
   /**动态路由参数，将被按顺序拼接到请求的url后面 */
   urlParams?: string[]
   /**请求成功时，是否返回完整响应数据，默认返回res.data */
   GetWholeResponse?: boolean
   /**请求是否需要登录才能发送，默认需要 */
   needLogin?: boolean
   [key: string]: any
}

export const successStatus = 200

const req_interceptors_sunccess: (config: any) => any = (config: myAxiosRequestConfig) => {
   if (!config.closeGlobalLoading)
      elLoading = ElLoading.service({ background: globalLoadingMaskBgColor, text: config.loadingTip ? config.loadingTip : '加载中...' })
   if (config.urlParams)
      config.url += "/" + config.urlParams.join('/')
   if (Object.keys(config).includes("needLogin") && !config.needLogin)
      return config
   config.cancelToken = new axios.CancelToken((c) => { cancelreq = c })
   const token = getToken()
   if (!token) {
      const { baseURL = '', url = '' } = config
      const cancelUrl = baseURL + url
      cancelreq(cancelMsgSymbol + cancelUrl)
   }
   else
      config.headers![tokenKey] = token
   return config
}
const req_interceptors_err = (err: AxiosError) => {
   console.log('req interceptors', err)
   elLoading && elLoading.close()
   const url = err.config?.url ? err.config.baseURL + err.config.url : "未知"
   const { code, message, msgToUser } = errResult.req_interceptors_err
   showMessage(url, msgToUser)
   return { code, message, err }
}
const res_interceptors_success = (res: AxiosResponse) => {
   elLoading && elLoading.close()
   const config = res.config as myAxiosRequestConfig
   const { message, code } = res.data
   if (code == undefined || code == successStatus) {     // 与后端沟通好，根据后端的业务状态码来写。此处表示只有200才成功
      if (config.GetWholeResponse) return res
      return res.data
   } else {
      const url = res.config?.url ? res.config.baseURL + res.config?.url : "未知"
      if (code === 401 || code === 403)
         logout()
      if (!config.closeErrTip)
         showMessage(url, message)
      return { code, message, err: res }
   }
}
const res_interceptors_err = (err: AxiosError<any, any>) => {
   console.log('res_interceptors_err', err)
   elLoading && elLoading.close()
   const url = err.config?.url ? err.config.baseURL + err.config.url : "未知"
   if (err.response) {
      const errMsg = err.response.data.message || err.message || '未知错误'
      // 根据服务器响应的状态码来统一处理响应。根据接口文档来写
      if (err.response.status === 401 || err.response.status === 403) {
         logout()
         const { code, message } = errResult.no_auth
         showMessage(url, message)
         return { code, message, err }
      }
      else if (err.response.status === 404) {
         const { code, message } = errResult.url_err
         showMessage(url, errMsg, false)
         return { code, message, err }
      }
      else if (err.response.status >= 500 && err.response.status <= 520) {
         const { code, message } = errResult.server_err
         showMessage(url, errMsg, false)
         return { code, message, err }

      } else {
         const { code, message } = errResult.unkown_err
         showMessage(url, errMsg, false)
         return { code, message, err }
      }
   }
   else {
      //console.log(err)
      if (err.message.startsWith(cancelMsgSymbol)) {
         logout()
         const { code, message, msgToUser } = errResult.req_cancel
         showMessage(err.message.split(cancelMsgSymbol)[1], msgToUser)
         return { code, message, err }
      }
      const { code, message } = errResult.network_err
      showMessage(url, message)
      return { code, message, err }
   }
}

service.interceptors.request.use(req_interceptors_sunccess, req_interceptors_err)
service.interceptors.response.use(res_interceptors_success, res_interceptors_err)


// 请求出错时返回结果的字典。这样就可以不需要使用try catch捕获请求错误了
const errResult = {
   'req_interceptors_err': { code: 1, message: '请求拦截出错！', msgToUser: '系统异常，请联系管理员！' },
   'req_cancel': { code: 2, message: '请求取消！', msgToUser: '请先登录！' },
   'network_err': { code: 3, message: '网络异常，请稍后再试！' },
   'no_auth': { code: 4, message: '无权访问！' },
   'server_err': { code: 5, message: '服务器繁忙！' },
   'url_err': { code: 6, message: '请求接口不存在！', msgToUser: '系统异常，请联系管理员！' },
   'unkown_err': { code: 7, message: '未知错误' },
}

function logout() {
   const user = useUserStore()
   user.logout(router.currentRoute.value.fullPath, false)
}


/**
 * @param url  请求路径 
 * @param msg  错误消息 
 * @param business_err  是否是业务错误，默认true
 */
function showMessage(url: string, msg: string, business_err = true) {
   if (import.meta.env.VITE_NODE_ENV === 'prod') {
      if (business_err) messageUtil.warning(msg)
      else messageUtil.error('服务器出错,请联系管理员！')
   }
   else {
      const baseUrl = import.meta.env.VITE_BASE_URL
      const _url = baseUrl ? url.split(baseUrl)[1] : url
      notification.error({
         title: '错误',
         dangerouslyUseHTMLString: true,
         message: `
                   <p>请求路径：</p>
                   <p>${_url}</p>
                   <p>错误原因:</p>
                   <p>${msg}</p>
                   `,
         // duration:100,
         duration: 0
      })
   }
}


/**
 * @description post请求 
 * @param reqUrl 
 * @param body 
 * @param config 
 * @returns 
 */
export function postReq(reqUrl: string, body = {}, config: myAxiosRequestConfig = {}): Promise<BasicResponseData> {
   return service({
      method: "post",
      url: reqUrl,
      data: body,
      ...config,
   })
}

/**
 * @description get请求 
 * @param reqUrl 
 * @param body 
 * @param config 
 * @returns 
 */
export function getReq(reqUrl: string, query = {}, config: myAxiosRequestConfig = {}): Promise<BasicResponseData> {
   return service({
      url: reqUrl,
      params: query,
      ...config,
   })
}

/**
 * @description 文件上传请求
 * @param reqUrl 
 * @param formData 
 * @param config 
 * @returns 
 */
export function uploadFileReq(reqUrl: string, formData: FormData, config: myAxiosRequestConfig = {}): Promise<BasicResponseData> {
   return service({
      url: reqUrl,
      method: 'post',
      headers: { 'Content-Type': 'multipart/form-data', },
      data: formData,
      ...config,
   })
}

/**
 * @description 获取blob的请求。当接口响应文件流时，请通过该请求函数配合 utils.downloadFileByBlob完成下载，utils.printFileByBlob完成打印
 * @param reqUrl 
 * @param method 
 * @param body 
 * @param config 
 * @returns 
 */
export function getBlobByFileStreamReq(reqUrl: string, method = 'get', reqParams = {}, config?: myAxiosRequestConfig) {
   const reqCfg = {
      method,
      url: reqUrl,
      responseType: 'blob' as any,
      ...{ GetWholeResponse: true, ...config },
   }
   if (method.toLowerCase() == 'get') reqCfg.params = reqParams
   else reqCfg.data = reqParams
   return service(reqCfg)
}